﻿#region Using Statements
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Neat;
using Neat.Mathematics;
using Neat.GUI;
using Neat.Graphics;
using Sectors;
using Microsoft.Xna.Framework.Input;
using System;
using System.Diagnostics;
using System.Windows.Forms;
using System.IO;
using System.Collections.Generic;
#endregion

namespace SectorsDesigner
{
    public partial class SectorsMapMakerControl : GraphicsDeviceControl
    {
        Vector2 offset;
        Color[] WallColors = new Color[]{
            Color.Tomato,
            Color.Yellow,
            Color.CornflowerBlue,
            Color.Gray};

        protected override void Draw()
        {
            var M = GetMousePosition(true);
            UpdateGame();

            GraphicsDevice.Clear(ClearOptions.DepthBuffer | ClearOptions.Target, Color.Black, 1.0f, 0);

            Set3DDrawingParameters();
            DrawSectors(Color.White);

            spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);

            DrawCenter(Color.Gray);
            if (ShowTriangles) DrawTriangles(Color.SlateBlue);
            DrawEdges(Color.Green);
            DrawVertices(Color.Red);

            switch (EditMode)
            {
                case EditModes.NewSector:
                    DrawFinishedPolygon(Color.Yellow);
                    break;
                case EditModes.SelectSector:
                    DrawSelectedSector(SelectColor);
                    DrawSectorPeekInfo(Color.White);
                    break;
                case EditModes.SelectEdge:
                    DrawSelectedEdge(SelectColor);
                    DrawWallPeekInfo(Color.White);
                    break;
                case EditModes.SelectVertex:
                    DrawSelectedVertex(SelectColor);
                    DrawVertexPeekInfo(Color.White);
                    break;
            }

            spriteBatch.Draw(logo, new Rectangle(Width - logo.Width - 10, Height - logo.Height - 10, logo.Width, logo.Height), GraphicsHelper.GetColorWithAlpha(Color.White, 0.5f));
            spriteBatch.Draw(crosshair, M + offset + crosshairOffset, Color.White);
            spriteBatch.DrawString(DesignerFont, r.Next().ToString(), new Vector2(23, Height - 23), Color.White);

            spriteBatch.End();
        }

        private void DrawTriangles(Color color)
        {
            foreach (var item in Polys)
            {
                foreach (var tri in item.Triangles) tri.Draw(spriteBatch, lb, offset, color);
            }
        }

        private void DrawCenter(Color color)
        {
            var M = GetMousePosition(true) + offset;
            spriteBatch.Draw(
                crosshair,
                GeometryHelper.Vectors2Rectangle(offset - crosshairOffset, crosshairOffset * 2), color);
            lb.Draw(spriteBatch, new LineSegment(0, M.Y, Width, M.Y), color);
            lb.Draw(spriteBatch, new LineSegment(M.X, 0, M.X, Height), color);
        }

        private void DrawVertexPeekInfo(Color color)
        {
            //throw new NotImplementedException();
        }

        private void DrawSelectedVertex(Color color)
        {
            if (Clock(ShowSelectedRate)) return;

            if (CurrentVertexIndex < 0) return;
            foreach (var item in Edges)
            {
                if (item.Indices.Contains(CurrentVertexIndex)) item.Draw(spriteBatch, tlb, color, offset);
            }
            spriteBatch.Draw(circle8x8, Vertices[CurrentVertexIndex] + offset + circle8x8Offset, color);
            spriteBatch.Draw(crosshair, Vertices[CurrentVertexIndex] + offset + crosshairOffset, color);
        }

        private void DrawWallPeekInfo(Color color)
        {
            //throw new NotImplementedException();
        }

        private void DrawSelectedEdge(Color color)
        {
            if (Clock(ShowSelectedRate)) return;

            if (CurrentEdgeIndex < 0) return;
            foreach (var item in SelectedEdgesIndices)
            {
                Edges[item].Draw(spriteBatch, lb, color, offset); 
            }
            Edges[CurrentEdgeIndex].Draw(spriteBatch, tlb, color, offset);
        }

        void Set3DDrawingParameters()
        {
            SamplerState ss = new SamplerState();
            ss.Filter = TextureFilter.Anisotropic;
            ss.AddressU = TextureAddressMode.Wrap;
            ss.AddressV = TextureAddressMode.Wrap;
            GraphicsDevice.SamplerStates[0] = ss;

            RasterizerState state = new RasterizerState();
            state.FillMode = FillMode.Solid;
            state.CullMode = CullMode.None;
            GraphicsDevice.RasterizerState = state;
        }

        private void DrawSectorPeekInfo(Color color)
        {
            for (int i = 0; i < Polys.Count; i++)
            {
                if (Polys[i].IsInside(MousePosition-offset))
                {
                    GraphicsHelper.DrawShadowedString(spriteBatch,DesignerFont, 
                        Sectors[i].Name + "\n" + 
                        "Floor/Ceiling: " +Sectors[i].FloorHeight.ToString() + "," + Sectors[i].CeilingHeight.ToString()+"\n"+
                        "Light: "+Sectors[i].LightIntensity.ToString() + "\n"+
                        "Textures: "+Sectors[i].FloorTexture+", " + Sectors[i].CeilingTexture,
                        MousePosition, color);
                    return;
                }
            }
        }

        void DrawSelectedSector(Color color)
        {
            if (Clock(ShowSelectedRate)) return;

            if (CurrentSectorIndex < 0)
                return;
            foreach (var item in SelectedSectorsIndices)
            {
                Polys[item].Draw(spriteBatch, lb, offset, color);
            }
            Polys[CurrentSectorIndex].Draw(spriteBatch, tlb, offset, color);
        }

        void DrawSectors(Color color)
        {
            if (SectorFillMode == SectorFillModes.Wire) return;
            for (int i = 0; i < Polys.Count; i++)
            {
                ColorFilterEffect.Parameters["mulColor"].SetValue(new Vector4(new Vector3(Sectors[i].LightIntensity), 1.0f));
                ColorFilterEffect.CurrentTechnique.Passes[0].Apply();
                if (SectorFillMode == SectorFillModes.Solid)
                    GraphicsDevice.Textures[0] = solid;
                else if ((HasTexture(Sectors[i].FloorTexture) && SectorFillMode == SectorFillModes.Floor) ||
                    (HasTexture(Sectors[i].CeilingTexture) && SectorFillMode == SectorFillModes.Ceiling))
                    GraphicsDevice.Textures[0] = GetTexture(SectorFillMode == SectorFillModes.Floor ? Sectors[i].FloorTexture : Sectors[i].CeilingTexture);
                Polys[i].Draw(GraphicsDevice, (Texture2D)GraphicsDevice.Textures[0], SectorFillMode == SectorFillModes.Floor ? Sectors[i].FloorUV : Sectors[i].CeilingUV, offset);
            }
        }

        void DrawEdges(Color color)
        {
            foreach (var e in AliveEdges)
            {
                    //TODO: Use Different colors for different types
                    int wtype = (int)Edges[e].Wall.WallType;
                    Edges[e].Draw(spriteBatch, lb, (wtype >= WallColors.Length) ? color : WallColors[wtype], offset);
                    //lb.Draw(spriteBatch, Vertices[Edges[e].Indices[i - 1]], Vertices[Edges[e].Indices[i]], palette[(int)Edges[e].Wall.WallType], offset);
                }
            
        }

        void DrawVertices(Color color)
        {
            for (int i = 0; i < Vertices.Count; i++)
			{
                if (DeletedVertices.Contains(i)) continue;
                spriteBatch.Draw(circle4x4, Vertices[i] + circle4x4Offset + offset, color);
            }
        }

        void DrawFinishedPolygon(Color color)
        {
            for (int p = 0, q = 1; q < newPolygonVertices.Count; p = q++)
            {
                lb.Draw(spriteBatch, newPolygonVertices[p], newPolygonVertices[q], color, offset);
            }
            //new Polygon(newPolygonVertices).Draw(spriteBatch, lb, offset, color);
            //if (CurrentEdgeIndex < 0) return;
            //if (Dummy == null) return;
            //if (Vertices.Count == 0 || Edges.Count == 0 || Dummy.Indices.Count == 0) return;
            //lb.Draw(spriteBatch, Vertices[LastVertexIndex] + offset, GetMousePosition(true) + offset, color);
            //lb.Draw(spriteBatch, Dummy.FirstEdge.FirstVertex + offset, GetMousePosition(true) + offset, color);
            if (newPolygonVertices.Count > 0)
            {
                lb.Draw(spriteBatch, newPolygonVertices[0], GetMousePosition(true), Color.Red, offset);
                lb.Draw(spriteBatch, newPolygonVertices[newPolygonVertices.Count-1], GetMousePosition(true), Color.Red, offset);
            }
        }

        void DrawGrid(Color color, float size)
        {
            //var dw = Width - offset.X;
            for (float r = 0; r < Math.Max(Width, Height); r += size)
            {
                lb.Draw(spriteBatch, new Vector2(r, 0), new Vector2(r, Height), color);
                lb.Draw(spriteBatch, new Vector2(0, r), new Vector2(Width, r), color);
            }
        }
    }
}